 package legoserver;


import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.io.*;
import java.net.*;
import javax.swing.*;
import javax.swing.event.*;
import com.sun.image.codec.jpeg.*;
import java.lang.Object.*;
import java.util.*;

public class Vision {
    //private float pictureX, pictureY,startX,startY;
    /*private Image image;
      private ImagePanel imagePanel;*/
    private BufferedImage bufferedImage; // holds the currently displayed image.
    //private final int red = 0xffff0000; // red color
    private final int red = 0xffff0000;
    private final int blue = 0xff0000ff; // blue color
    private final int white = 0xffffffff; // white color
    private final int black = 0xff000000; // black color
    private final int gray = 0xff555555; // gray color
    private final int yellow = 0xffffff00;  //yellow color
    private final int lightgray = 0xff888888; // light gray color
    //private boolean isclicked=false;     //to tell if they clicked on the image
    //private ImageIcon mazeIcon = new ImageIcon("maze.jpg");
    //private JLabel mazeImg = new JLabel(mazeIcon);
    //private Exception exception = null;
    private ImageTransformation trans = new ImageTransformation();
    //private int mouseclicks = 0;
    
    //Link to parent thread
    private LegoMazePathfinder pFinder;
    
    private AStar astar;
       
    
    /*public void refreshImage(Image i) {
        busy = true;
        bufferedImage = getBufferedImage(i);
        mazeIcon = new ImageIcon(i);
        mazeImg = new JLabel(mazeIcon);
        busy = false;
    }*/
    /*
    public void mouseReleased(MouseEvent e){}
    public void mouseExited(MouseEvent e){}
    public void mouseClicked(MouseEvent e){
        mouseclicks++;
    }
    public void mouseEntered(MouseEvent e){}
    public void mousePressed(MouseEvent e){
        int x, y;
        if(mouseclicks==1){
        pictureX = (float)e.getX()/ (float) mazeImg.getWidth();
        pictureY = (float)e.getY()/ (float) mazeImg.getHeight();
           isclicked = true;    
        }
        if(mouseclicks==0){
        startX = (float)e.getX()/ (float) mazeImg.getWidth();
        startY = (float)e.getY()/ (float) mazeImg.getHeight();     
     
        }

    }*/
    
    /*public void refreshImg(Image newImage) {
        addImage(getBufferedImage(newImage));
    }*/
    
    /*public void setCoords (Point curCoord, Point destCoord) {
        busy = true;
        //we need to normalize the coords into the img
        startX = (float)curCoord.x; // / (float)mazeImg.getWidth();
        startY = (float)curCoord.y; // / (float)mazeImg.getHeight();
        
        pictureX = (float)destCoord.x; // / (float)mazeImg.getWidth();
        pictureY = (float)destCoord.y; // / (float)mazeImg.getHeight();
        busy = false;
    }*/

    /**
     * constructor builds the main user interface
     */
    public Vision(LegoMazePathfinder pFinder) {
        this.pFinder = pFinder;
    }
    
    /**
     * transforms Buffered Image
     * @param operation effect operation
     */
   public void transformImage(String operation) {
        if (null != bufferedImage) {
            bufferedImage = trans.transImage(operation, bufferedImage);
        }
   }
    
    /**
     * does the transformation of the original image to a very reduced one
     * using different image operations
     */
    public void effectImage() {
        transformImage("Blur 4x4");
        transformImage("Threshold 192");
        transformImage("Scale 0.25");
        getBW();
        transformImage("Blur 4x4");
        transformImage("Blur 4x4");
        transformImage("Blur 4x4");
        transformImage("Blur 4x4");
        getWalls();
        transformImage("Scale 0.5");       
    }
    
    /**
     * changes red and blue color to black, the rest to white
     */
    public void getBW() {
        int w = bufferedImage.getWidth(null);
        int h = bufferedImage.getHeight(null);
        for (int i = 0; i < h; i++) {
            for (int j = 0; j < w; j++) {
                int pixel = bufferedImage.getRGB(j, i);
                if ((pixel == red) || (pixel == yellow)) {
                    bufferedImage.setRGB(j, i, black); // make black
                } else { bufferedImage.setRGB(j, i, white); } // make white
            }
        }
    }
    
    /**
     * sets every pixel which is not absolutly white to black
     */
    public void getWalls() {
        int w = bufferedImage.getWidth(null);
        int h = bufferedImage.getHeight(null);
        for (int i = 0; i < h; i++) {
            for (int j = 0; j < w; j++) {
                int pixel = bufferedImage.getRGB(j, i);
                if (pixel != white) {
                    bufferedImage.setRGB(j, i, black); // make black
                } else { bufferedImage.setRGB(j, i, white); } // make white
            }
        }
    }
    
    /**
     * gets values with different costs for the A* search
     * @return int array with cost values
     */
    public int[][] getMaze() {
        int w = bufferedImage.getWidth(null);
        int h = bufferedImage.getHeight(null);
        int[][] maze = new int[w][h];
        for (int i = 0; i < h; i++) {
            for (int j = 0; j < w; j++) {
                int pixel = bufferedImage.getRGB(j, i);
                if (pixel < gray) {
                    maze[j][i] = 100;
                    bufferedImage.setRGB(j, i, black); // make black
                }
                if ((pixel < lightgray) && (pixel >= gray)) {
                    maze[j][i] = 10;
                    bufferedImage.setRGB(j, i, gray); // make gray
                } else if ((pixel >= gray) && (pixel != white)) {
                    maze[j][i] = 5;
                    bufferedImage.setRGB(j, i, lightgray); // make ligthgray
                }
            }
        }
        return maze;
    }     
    /**
     * creates a filedialog for selecting a file
     * @param mode (save or load)
     * @return path of located file
     */
    /*public String getPath(int mode) {
        FileDialog fd = new FileDialog(Vision.this, "", mode);
        fd.setFile("*.jpg");
        fd.show();
        if (fd.getFile() == null) return "";
        String path = fd.getDirectory() + fd.getFile();
        return path;
    }*/
    /**
     * makes a BufferedImage from an image
     * @param image
     * @return BufferedImage
     */
    public BufferedImage getBufferedImage(Image image) {
        int width = image.getWidth(null);
        int height = image.getHeight(null);
        bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        Graphics2D g = bufferedImage.createGraphics();
        g.drawImage(image, null, null);
        
        return bufferedImage;
    }
    
    /**
     * this method returns an Image object from a buffered image
     * @param bufferedImage
     * @return Image
     */
    /*public static Image toImage(BufferedImage bufferedImage) {
        return Toolkit.getDefaultToolkit().createImage(bufferedImage.getSource());
    }*/
    
    /**
     * adds image to the innerPane
     * @param bufferedImage
     */
    
    /*public void addImage(BufferedImage bufferedImage) {
        imagePanel = new ImagePanel(bufferedImage);
        repaint();
    }*/
    
    /**
     * gets URL of an icon in the class path
     * @param path path of the icon relative to the classes
     * @return URL of the icon
     */
    public URL getIcon(String path) {
        return Vision.class.getResource(path);
    }
    
    /**
     * destroy object
     * @param object
     */
    /*public static void destroy(Object object) {
        // dispose();
    }
    public void doAll(){
        // wait for user to click on the image before running
        while (!isclicked){
        }
        Image image = Toolkit.getDefaultToolkit().getImage("maze.jpg");
        MediaTracker mediaTracker = new MediaTracker(this);
        mediaTracker.addImage(image, 0);
        try { mediaTracker.waitForID(0); } catch (InterruptedException e) { System.err.println(e); }
        addImage(getBufferedImage(image));
        startAStar();      
    }*/
    /**
     * start A* search module
     */
    public void doAStar(Image i, Point start, Point end) {
        float startX, startY, endX, endY;
        
        bufferedImage = getBufferedImage(i);
        /*
        update("start: x=" + start.x + ",y=" + start.y);
        update("end: x=" + end.x + ",y=" + end.y);
        
        update("bufferedImage.getWidth()=" + bufferedImage.getWidth());
        update("bufferedImage.getHeight()=" + bufferedImage.getHeight());*/
        
        //get start coords as percent
        startX = (float)start.x / (float)bufferedImage.getWidth();
        startY = (float)start.y / (float)bufferedImage.getHeight();
        
        //get end coords as percent
        endX = (float)end.x / (float)bufferedImage.getWidth();
        endY = (float)end.y / (float)bufferedImage.getHeight();
        
        update("startX=" + startX);
        update("startY=" + startY);
        update("endX=" + endX);
        update("endY=" + endY);
        
        astar = new AStar();
        float fixedHeight, picW, picH;
        if (bufferedImage != null) {
            effectImage();
            astar.setMaze(getMaze(), bufferedImage.getWidth(null), bufferedImage.getHeight(null));
        }
        /*astar.setSize(730, 730);
        astar.setResizable(false);
        astar.setTitle("A* Search");*/
        //This part sets the start
        picW= (float)bufferedImage.getWidth();
        picH= (float)bufferedImage.getHeight();
        fixedHeight = (picH/picW);
        astar.map.gridCell[(int)Math.round(startX*astar.map.w)][(int)1+Math.round((startY*astar.map.h)*fixedHeight)].setStart(true);
        //This part sets the finish
        picW= (float)bufferedImage.getWidth();
        picH= (float)bufferedImage.getHeight();
        fixedHeight = (picH/picW);
        astar.map.gridCell[(int)Math.round(endX*astar.map.w)][(int)1+Math.round((endY*astar.map.h)*fixedHeight)].setFinish(true);
        
        astar.finder.findPath(astar.map);
        
        //run the path
        
        //astar.addWindowListener(new WindowAdapter() {
            //public void windowClosing(WindowEvent e) { astar.destroy();}});
    }
    
    public Vector getSolution() {
        return astar.finder.getSolution();
    }
    
    public void printMap() {
        for(int y = 0; y < astar.map.h; y++) {
            for(int x = 0; x < astar.map.w; x++) {
                if(astar.map.gridCell[x][y].isUsed())
                    System.out.print("X");
                else
                    System.out.print(" ");
            }
            System.out.println();
        }
    }
    
    public boolean isBusy() {
        return astar.isBusy();
    }
    
    private void update(String s) {
        pFinder.update(s);
    }
}